package redis

import (
	"context"
	"errors"
	"github.com/go-redis/redis/v8"
	"internal/codec"
	"internal/util"
	"time"
)

type RedisConn struct {
	addr     string
	password string
	dbname   int
	poolsize int
	conn     *redis.Client
}

var redis_ *RedisConn
var ctx = context.Background()

func InitRedisCache() error {
	// 设置连接超时
	redis_ = &RedisConn{
		addr:     "82.156.87.105:6379",
		password: "redis594188",
		dbname:   0,
		poolsize: 50,
		conn:     nil,
	}
	client := redis.NewClient(&redis.Options{
		Network:      "tcp",
		Addr:         redis_.addr,
		Password:     redis_.password,
		DB:           redis_.dbname,
		DialTimeout:  5 * time.Second,
		ReadTimeout:  30 * time.Second,
		WriteTimeout: 30 * time.Second,
		PoolSize:     redis_.poolsize, //连接池个数
		PoolTimeout:  30 * time.Second,
		MinIdleConns: 10,               // 最小空闲连接数
		IdleTimeout:  30 * time.Second, // 连接最大空闲时间
	})
	ping, err := client.Ping(ctx).Result()
	if err != nil {
		util.LogSrv.Error("[InitRedisStore] Redis Init Err: %s, %v", ping, err)
		return err
	}
	util.LogSrv.Info("[InitRedisStore] Redis Init Success!")
	redis_.conn = client
	return nil
}

// 公共调用方法
// 获取redis连接
func GetRedisConn() *redis.Client {
	return redis_.getConn()
}

// 存入哈希
func RedisHashSet(table string, key string, value interface{}, expireTime int) error {
	return redis_.HashSet(table, key, value, expireTime)
}

// 读取哈希表的数据
func RedisHashGet(table string, key string, value interface{}) error {
	return redis_.HashGet(table, key, value)
}

// 删除哈希表的字段
func RedisHashDel(table string, key string) error {
	return redis_.HashDel(table, key)
}

/*
redis调用公共方法
*/
func (r *RedisConn) getConn() *redis.Client {
	return r.conn
}

/*
封装哈希表设置缓存

	HashSet:将哈希存储数据序列化
	HashGet:读取哈希存储序列化数据
*/
func (r *RedisConn) HashSet(table string, key string, value interface{}, expireTime int) error {
	if r.conn == nil {
		util.LogSrv.Error("[Redis] Redis Conn Fail!")
		return errors.New("Redis conn fail!")
	}
	//先序列化
	stream, err := codec.Marshal(value)
	if err != nil {
		util.LogSrv.Error("[Codec] codec Marshal fail!, table=[%s], Key=[%s], Err=[%v]", table, key, err)
		return err
	}
	// 再写缓存
	err = r.conn.HSet(ctx, table, key, stream).Err()
	if err != nil {
		util.LogSrv.Error("[Redis] HSet Redis Fail!, Table=[%s], Key=[%s], Err=[%v]", table, key, err)
		return err
	}
	// 设置哈希存过期时间
	expire := time.Duration(expireTime) * time.Second
	err = r.conn.Expire(ctx, table, expire).Err()
	if err != nil {
		util.LogSrv.Error("[Redis] Expire Redis Fail!, Table=[%s], Key=[%s], Err=[%v]", table, key, err)
		return err
	}
	// 验证哈希表过期时间是否成功
	ttl, err := r.conn.TTL(ctx, table).Result()
	if err != nil {
		util.LogSrv.Error("[Redis] HSet expireTime set Fail!, Table=[%s], Key=[%s], Err=[%v]", table, key, err)
		return err
	}
	util.LogSrv.Debug("[Redis] HSet Redis Success!, Table=[%s], Key=[%s] ,TTL=[%vs]", table, key, ttl.Seconds())
	return nil
}

func (r *RedisConn) HashGet(table string, key string, value interface{}) error {
	if r.conn == nil {
		util.LogSrv.Error("[Redis] Redis Conn Fail!")
		return errors.New("Redis conn fail!")
	}
	// 读取缓存
	stream, err := r.conn.HGet(ctx, table, key).Result()
	if err != nil {
		util.LogSrv.Error("[Redis] HGet Redis Fail!, Table=[%s], Key=[%s] ,Err=[%v]", table, key, err)
		return err
	}
	// 对缓存解码序列化
	err = codec.Unmarshal([]byte(stream), &value)
	if err != nil {
		util.LogSrv.Error("[Codec] codec UnMarshal fail, Table=[%s], Key=[%s], Err=[%vs]", table, key, err)
		return err
	}
	util.LogSrv.Debug("[Redis] HGet Redis Success!, Table=[%s], Key=[%s]", table, key)
	return nil
}

func (r *RedisConn) HashDel(table string, key string) error {
	if r.conn == nil {
		util.LogSrv.Error("[Redis] Redis Conn Fail!")
		return errors.New("Redis conn fail!")
	}
	err := r.conn.HDel(ctx, table, key).Err()
	if err != nil {
		util.LogSrv.Error("[Redis] HDel Redis Fail!, Table=[%s], Key=[%s], Err=[%v]", table, key, err)
		return err
	}
	util.LogSrv.Info("[Redis] HDel Redis Success!, Table=[%s], Key=[%s]", table, key)
	return nil
}
